#![allow(unused_imports)]
#![allow(unreachable_patterns)]
#![allow(unused_variables)]
#![allow(unused_assignments)]
#![allow(unused_must_use)]
#![allow(dead_code)]

#[macro_use]
extern crate lazy_static;

use std::convert::Infallible;
use std::sync::Mutex;
use std::thread::sleep;
use std::time::Duration;

use chrono::DateTime;
use fast_log::log::RuntimeType;
use log::info;
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use tide::Request;

use rbatis::crud::{CRUD, CRUDEnable};
use rbatis::plugin::page::{IPageRequest, Page, PageRequest};
use rbatis::rbatis::Rbatis;
use rbatis::wrapper::Wrapper;
use rbatis_core::db::DBPool;
use rbatis_core::types::chrono::NaiveDateTime;

mod crud_test;

///数据库表模型,支持BigDecimal ,DateTime ,rust基本类型（int,float,uint,string,Vec,Array）
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct BizActivity {
    pub id: Option<String>,
    pub name: Option<String>,
    pub pc_link: Option<String>,
    pub h5_link: Option<String>,
    pub pc_banner_img: Option<String>,
    pub h5_banner_img: Option<String>,
    pub sort: Option<String>,
    pub status: Option<i32>,
    pub remark: Option<String>,
    pub create_time: Option<NaiveDateTime>,
    pub version: Option<i32>,
    pub delete_flag: Option<i32>,
}

impl CRUDEnable for BizActivity {
    type IdType = String;
}


//示例 mysql 链接地址
pub const MYSQL_URL: &'static str = "mysql://root:123456@localhost:3306/test";

// 示例-Rbatis示例初始化(必须)
lazy_static! {
  static ref RB:Rbatis=Rbatis::new();
}


//启动web服务，并且对表执行 count统计
#[async_std::main]
async fn main() {
    fast_log::log::init_log("requests.log", &RuntimeType::Std).unwrap();
    RB.link(MYSQL_URL).await.unwrap();
    let mut app = tide::new();
    app.at("/").get(|_: Request<()>| async move {
        // println!("accept req[{} /test] arg: {:?}",req.url().to_string(),a);
        let arg = &vec![json!(1)];
        let v = RB.fetch_prepare("", "SELECT count(1) FROM biz_activity where delete_flag = ?;", arg).await;
        if v.is_ok() {
            let data: Value = v.unwrap();
            Ok(data.to_string())
        } else {
            Ok(v.err().unwrap().to_string())
        }
    });
    //app.at("/").get(|_| async { Ok("Hello, world!") });
    let addr = "0.0.0.0:8000";
    println!("http server listen on http://{}", addr);
    app.listen(addr).await.unwrap();
}


// 示例-打印日志
#[test]
pub fn test_log() {
    //1 启用日志(可选，不添加则不加载日志库)
    fast_log::log::init_log("requests.log", &RuntimeType::Std).unwrap();
    info!("print data");
    sleep(Duration::from_secs(1));
}

//示例-Rbatis直接使用驱动
#[test]
pub fn test_use_driver() {
    async_std::task::block_on(
        async move {
            fast_log::log::init_log("requests.log", &RuntimeType::Std).unwrap();
            let pool = DBPool::new(MYSQL_URL).await.unwrap();
            let mut conn = pool.acquire().await.unwrap();
            let mut c = conn.fetch("SELECT count(1) FROM biz_activity;").unwrap();
            let r: serde_json::Value = c.decode_json().await.unwrap();
            println!("done:{:?}", r);
        }
    );
}

//示例-Rbatis直接使用驱动-prepared stmt sql
#[test]
pub fn test_prepare_sql() {
    async_std::task::block_on(
        async move {
            fast_log::log::init_log("requests.log", &RuntimeType::Std).unwrap();
            let rb = Rbatis::new();
            rb.link(MYSQL_URL).await.unwrap();
            let arg = &vec![json!(1), json!("test%")];
            let r: Vec<BizActivity> = rb.fetch_prepare("", "SELECT * FROM biz_activity WHERE delete_flag =  ? AND name like ?", arg).await.unwrap();
            println!("done:{}", serde_json::to_string(&r).unwrap_or(String::new()));
            //
            // let a=r.get(0).unwrap();
            // rb.save(a).await.unwrap();
        }
    );
}


//示例-Rbatis使用py风格的语法查询
#[test]
pub fn test_py_sql() {
    async_std::task::block_on(async move {
        fast_log::log::init_log("requests.log", &RuntimeType::Std).unwrap();
        let rb = Rbatis::new();
        rb.link(MYSQL_URL).await.unwrap();
        let py = r#"
    SELECT * FROM biz_activity
    WHERE delete_flag = #{delete_flag}
    if name != null:
      AND name like #{name+'%'}
    if ids != null:
      AND id in (
      trim ',':
         for item in ids:
           #{item},
      )"#;
        let data: serde_json::Value = rb.py_fetch("", py, &json!({   "delete_flag": 1 })).await.unwrap();
        println!("{}", data);
    });
}

//示例-Rbatis语法分页
#[test]
pub fn test_sql_page() {
    async_std::task::block_on(async move {
        fast_log::log::init_log("requests.log", &RuntimeType::Std).unwrap();
        let rb = Rbatis::new();
        rb.link(MYSQL_URL).await.unwrap();
        let wraper = rb.new_wrapper()
            .eq("delete_flag", 1).check().unwrap();
        let data: Page<BizActivity> = rb.fetch_page_by_wrapper("", &wraper, &PageRequest::new(1, 20)).await.unwrap();
        println!("{}", serde_json::to_string(&data).unwrap());
    });
}

//示例-Rbatis使用py风格的语法分页
#[test]
pub fn test_py_sql_page() {
    async_std::task::block_on(async move {
        fast_log::log::init_log("requests.log", &RuntimeType::Std).unwrap();
        let rb = Rbatis::new();
        rb.link(MYSQL_URL).await.unwrap();
        let py = r#"
    SELECT * FROM biz_activity
    WHERE delete_flag = #{delete_flag}
    if name != null:
      AND name like #{name+'%'}"#;
        let data: Page<BizActivity> = rb.py_fetch_page("", py, &json!({   "delete_flag": 1 }), &PageRequest::new(1, 20)).await.unwrap();
        println!("{}", serde_json::to_string(&data).unwrap());
    });
}

//示例-Rbatis使用传统XML风格的语法查询
#[test]
pub fn test_xml_sql() {
    async_std::task::block_on(
        async move {
            fast_log::log::init_log("requests.log", &RuntimeType::Std).unwrap();
            let mut rb = Rbatis::new();
            rb.link(MYSQL_URL).await.unwrap();
            //xml数据建议以 XXMapper.xml 的格式存储管理
            rb.load_xml("test", r#"
<mapper>
    <sql id="columns">id,name,pc_link,h5_link,pc_banner_img,h5_banner_img,sort,status,remark,version,create_time,delete_flag</sql>
    <select id="select_by_condition">
        <bind name="pattern" value="'%' + name + '%'"/>
        select <include refid="columns"/> from biz_activity
        <where>
            <if test="name != null">and name like #{pattern}</if>
            <if test="startTime != null">and create_time >= #{startTime}</if>
            <if test="endTime != null">and create_time &lt;= #{endTime}</if>
        </where>
        order by create_time desc
        <if test="page != null and size != null">limit #{page}, #{size}</if>
    </select>
</mapper>"#).unwrap();
            let arg = &json!({
            "delete_flag": 1,
            "name": "test",
            "startTime": null,
            "endTime": null,
            "page": 0,
            "size": 20
            });
            let data: Vec<BizActivity> = rb.xml_fetch("", "test", "select_by_condition", arg).await.unwrap();
            println!("{}", serde_json::to_string(&data).unwrap_or("".to_string()));
        }
    )
}

//示例-Rbatis使用事务
#[test]
pub fn test_tx() {
    async_std::task::block_on(async {
        fast_log::log::init_log("requests.log", &RuntimeType::Std).unwrap();
        let rb = Rbatis::new();
        rb.link(MYSQL_URL).await.unwrap();
        let tx_id = "1";
        rb.begin(tx_id).await.unwrap();
        let v: serde_json::Value = rb.fetch(tx_id, "SELECT count(1) FROM biz_activity;").await.unwrap();
        println!("{}", v.clone());
        rb.commit(tx_id).await.unwrap();
    });
}

/// 示例-Rbatis使用web框架Tide、async_std
#[test]
pub fn test_tide() {
    async_std::task::block_on(async {
        fast_log::log::init_log("requests.log", &RuntimeType::Std).unwrap();
        RB.link(MYSQL_URL).await.unwrap();
        let mut app = tide::new();
        app.at("/").get(|_: Request<()>| async move {
            // println!("accept req[{} /test] arg: {:?}",req.url().to_string(),a);
            let v = RB.fetch("", "SELECT count(1) FROM biz_activity;").await;
            if v.is_ok() {
                let data: Value = v.unwrap();
                Ok(data.to_string())
            } else {
                Ok(v.err().unwrap().to_string())
            }
        });
        //app.at("/").get(|_| async { Ok("Hello, world!") });
        let addr = "0.0.0.0:8000";
        println!("server on http://{}", addr);
        app.listen(addr).await.unwrap();
    });
}


async fn hello(_: hyper::Request<hyper::Body>) -> Result<hyper::Response<hyper::Body>, Infallible> {
    let v = RB.fetch("", "SELECT count(1) FROM biz_activity;").await;
    if v.is_ok() {
        let data: Value = v.unwrap();
        Ok(hyper::Response::new(hyper::Body::from(data.to_string())))
    } else {
        Ok(hyper::Response::new(hyper::Body::from(v.err().unwrap().to_string())))
    }
}

// 示例-Rbatis使用web框架hyper/Tokio
#[tokio::main]
#[test]
pub async fn test_hyper() {
    // 实例化 运行时
    // let RT:Mutex<tokio::runtime::Runtime> = Mutex::new(tokio::runtime::Builder::new()
    //     .basic_scheduler()
    //     .enable_all()
    //     .build()
    //     .unwrap());
    fast_log::log::init_log("requests.log", &RuntimeType::Std).unwrap();
    RB.link(MYSQL_URL).await.unwrap();
    let make_svc = hyper::service::make_service_fn(|_conn| {
        async { Ok::<_, Infallible>(hyper::service::service_fn(hello)) }
    });
    let addr = ([0, 0, 0, 0], 8000).into();
    let server = hyper::Server::bind(&addr).serve(make_svc);
    println!("Listening on http://{}", addr);
    server.await.unwrap();
}